//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            listImpl.h
// AUTHOR:          Vladimir Gumenuk
// DATE:            28-Mar-2013
// 
// NOTES: This file created to separate implementation of some template XVM methods.
//        This is the point, when the power of the templates get lost...
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include "xort.h"

#ifdef __XVM__
#define LPCSTR  const char*
#include "xruntime.h"
#include "BuildinObjectInfo.h"

#define IMPLEMENT_OBJECT_INFO() \
    private: static BuildInObjectInfo m_ObjectInfo; \
    public: \
    virtual int Init( symbolref pSymbol, XortNativeInterface *pExternalObj ) { return m_ObjectInfo.Init( pSymbol ); } \
    virtual void Uninit() { m_ObjectInfo.Uninit(); } \
    virtual symbolref get_Symbol() { return m_ObjectInfo.get_Symbol(); } \
    virtual symbolref get_Method( dword dwIdx ) { return m_ObjectInfo.get_Method( dwIdx ); } 


template<typename ListIteratorType, typename ListClass>
class CXListIteratorImpl : public xobject
{
public:
    typedef typename ListClass::iterator xlistIterator;
private:
    xlistIterator       m_theIterBegin;
    xlistIterator       m_theIterEnd;
    xlistIterator       m_theIterWork;
    dword               m_dwTemplateType; // this is the type of template argument

public:
    CXListIteratorImpl() { m_dwType = t_listiter; m_dwTemplateType = 0xFFFFFFFF; }
    CXListIteratorImpl( dword dwTemplateType ) { m_dwType = t_listiter; m_dwTemplateType = dwTemplateType; }
    CXListIteratorImpl( xlistIterator& iterBegin, xlistIterator& iterEnd, xlistIterator& iterWrk, int typeVal ) 
        : m_theIterBegin( iterBegin ), m_theIterEnd( iterEnd ), m_theIterWork( iterWrk )
      {
          m_dwType = t_listiter;
          m_dwTemplateType = typeVal; 
      }

    virtual ~CXListIteratorImpl() { ; }

IMPLEMENT_OBJECT_INFO();

    static symbolref __GetSymbol() { return m_ObjectInfo.get_Symbol(); }

    void SetInternalIterators( xlistIterator& iterBegin, xlistIterator& iterEnd, xlistIterator& iterWrk, int typeVal )
    {
        m_theIterBegin = iterBegin; m_theIterEnd = iterEnd; m_theIterWork = iterWrk;
        m_dwTemplateType = typeVal; 
    }

    dword GetTemplateType() { return m_dwTemplateType; }
    virtual dword GetType() { return t_listiter; }

    xlistIterator get_Iterator() { return m_theIterWork; }

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        int iRet = XORT_OK;

        XCELLSARRAY& stack = pRuntime->get_Stack();
        const XortElement& sysFrame = stack.top();
        if( sysFrame.bAccess != sys_Frame ) return ERR_INVALID_STACK_SYSFRAME;
        dword dwArgsCount = sysFrame.bType;
        
        InstructionData retPrim; retPrim.m_bInstrCode = p_ret; retPrim.m_bTypeAddr = t_v; // prepare ret primitive
        XortElement retVal; retVal.bAccess = usr_VarRW; // prepare return value

        switch( dwFuncIndex )
        {
        case 1:    // 1 T next();
            {
                if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;
                
                if( m_theIterWork.isContainerValid() ) { // ensure internal container object is valid
                    ListIteratorType val = (ListIteratorType)m_theIterWork;
                    retVal.SetValue( val );
                }
                
                m_theIterWork++;
                                
                retVal.bType = t_p; // m_dwTemplateType // what about to return t_p for all objects here?

                iRet = pRuntime->do_ret( retPrim );
                if( iRet != XORT_OK ) return iRet;

                stack.push( retVal );
                break;
            }
        case 2:    // 2 T prev();
            {
                if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

                if( m_theIterWork.isContainerValid() ) { // ensure internal container object is valid
                    ListIteratorType val = (ListIteratorType)m_theIterWork;
                    retVal.SetValue( val );
                }
                
                m_theIterWork--;
                                
                retVal.bType = t_p; // m_dwTemplateType; // what about to return t_p for all objects here?

                iRet = pRuntime->do_ret( retPrim );
                if( iRet != XORT_OK ) return iRet;

                stack.push( retVal );
                break;
            }
        case 3:    // 3 void reset_to_begin();
            {
                if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;
                m_theIterWork = m_theIterBegin;

                iRet = pRuntime->do_ret( retPrim );
                if( iRet != XORT_OK ) return iRet;

                break;
            }
        case 4:    // 4 void reset_to_end();
            {
                if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;
                m_theIterWork = m_theIterEnd;
                
                iRet = pRuntime->do_ret( retPrim );
                if( iRet != XORT_OK ) return iRet;

                break;
            }
        case 5:     // 5 T item();
            {
                  if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

                  if( m_theIterWork.isContainerValid() ) { // ensure internal container object is valid
                      ListIteratorType val = ( ListIteratorType )m_theIterWork;
                      retVal.SetValue( val );
                  }

                  retVal.bType = t_p; // m_dwTemplateType // what about to return t_p for all objects here?

                  iRet = pRuntime->do_ret( retPrim );
                  if( iRet != XORT_OK ) return iRet;

                  stack.push( retVal );
                  break;
            }
        default:
            return ERR_METHOD_NOT_FOUND;
        }

        return XORT_OK;
    }

    virtual int Put( dword dwVarIndex, const XortElement& Value ) { 
        return ERR_METHOD_NOT_IMPL;
    }
    virtual int Get( dword dwVarIndex, XortElement& Value ) { 
        return ERR_METHOD_NOT_IMPL; 
    }
    virtual dword GetVariablesCount() { return 0; }
};

template<class ListClass, typename ListType, int typeValue>
int InvokeListMethod( ListClass *pList, dword dwFuncIndex, XRuntime *pRuntime )
{
    int iRet = XORT_OK;

    XCELLSARRAY& stack = pRuntime->get_Stack();
    const XortElement& sysFrame = stack.top();
    if( sysFrame.bAccess != sys_Frame ) return ERR_INVALID_STACK_SYSFRAME;
    dword dwArgsCount = sysFrame.bType;
    dword dwStackBase = pRuntime->get_StackBase();

    InstructionData retPrim; retPrim.m_bInstrCode = p_ret; retPrim.m_bTypeAddr = t_v; // prepare ret primitive
    XortElement retVal; retVal.bAccess = usr_VarRW; // prepare return value

    switch( dwFuncIndex )
    {
    case 1:    // 1 void clear();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            pList->clear();

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            break;
        }

    case 2:    // 2 dword push_front( const T& Item );
        {
            if( dwArgsCount != 1 ) return ERR_INVALID_ARG_COUNT;

            XortElement& argItem = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != pList->GetTemplateType() || argItem.bType != typeValue ) return ERR_INVALID_TYPE;

            retVal._u4 = pList->push_front( (ListType)argItem );
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 3:    // 3 dword push_back( const T& Item );
        {
            if( dwArgsCount != 1 ) return ERR_INVALID_ARG_COUNT;

            XortElement& argItem = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != pList->GetTemplateType() || argItem.bType != typeValue ) return ERR_INVALID_TYPE;

            retVal._u4 = pList->push_back( (ListType)argItem );
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 4:    // 4 dword pop_front();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            retVal._u4 = pList->pop_front();
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 5:    // 5 dword pop_back();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            retVal._u4 = pList->pop_back();
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 6:    // 6 dword size();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            retVal._u4 = pList->size();
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 7:    // 7 void reset_to_begin();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            pList->reset_to_begin();
            
            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            break;
        }

    case 8:    // 8 const T* next();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            const ListType* val = pList->next();
            if( val )
                retVal.SetValue( *val );

            retVal.bType = typeValue;
    
            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 9:    // 9 void reset_to_end();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            pList->reset_to_end();

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            break;
        }

    case 10:   // 10 const T* prev();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;

            const ListType *val = pList->prev();
            if( val )
                retVal.SetValue( *val );

            retVal.bType = typeValue;
            
            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    case 11:   // 11 dword copy( list Dst );
        {
            if( dwArgsCount != 1 ) // check arguments
                return ERR_INVALID_ARG_COUNT;

            XortElement& argItem  = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != t_p ) return ERR_INVALID_TYPE;
            if( argItem._p == NULL ) return ERR_INVALID_ARG;
            if( argItem._p->GetType() != t_list ) return ERR_INVALID_TYPE;

            ListClass *pLst = (ListClass*)argItem._p;
            if( pLst->GetTemplateType() != pList->GetTemplateType() ) return ERR_INVALID_TYPE;

            retVal._u4   = pList->copy( *pLst ); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure to the stack
            break;
        }

    case 12:   // 12 ListIterator begin();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;
            typename ListClass::iterator theIterBegin = pList->begin();
            typename ListClass::iterator theIterEnd = pList->end();

            CXListIteratorImpl<ListType, ListClass> *pIter = new CXListIteratorImpl<ListType, ListClass>( theIterBegin, theIterEnd, theIterBegin, typeValue );
            if( !pIter )
                return ERR_MEMORY_ALLOCATION;

            symbolref pIterSymbol = CXListIteratorImpl<ListType, ListClass>::__GetSymbol();
            if( pIterSymbol ) { // fast way, try to get symbol from the same iterator type if any
                pIter->Init( pIterSymbol, NULL );
            } else { // looks like we create this iterator for the first time, look to symbol table
                SYMBOLLIST symList = pRuntime->get_GlobalSymbolList();
                symbolref pListSym = pList->get_Symbol();
                SymbolRef iterSymbol = FindTemplateType( symList, t_listiter, pListSym->m_dwTemplSpecType );
                iRet = pIter->Init( &iterSymbol, NULL );
                if( iRet != XORT_OK ) {
                    delete pIter;
                    return iRet;
                }
            }

            retVal.SetValue( pIter ); // +ref
            retVal.bType = t_p;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal );
            break;
        }

    case 13:   // 13 ListIterator end();
        {
            if( dwArgsCount != 0 ) return ERR_INVALID_ARG_COUNT;
            typename ListClass::iterator theIterBegin = pList->begin();
            typename ListClass::iterator theIterEnd = pList->end();

            CXListIteratorImpl<ListType, ListClass> *pIter = new CXListIteratorImpl<ListType, ListClass>( theIterBegin, theIterEnd, theIterEnd, typeValue );
            if( !pIter )
                return ERR_MEMORY_ALLOCATION;

            symbolref pIterSymbol = CXListIteratorImpl<ListType, ListClass>::__GetSymbol();
            if( pIterSymbol ) { // fast way, try to get symbol from the same iterator type if any
                pIter->Init( pIterSymbol, NULL );
            } else { // looks like we create this iterator for the first time, look to symbol table
                SYMBOLLIST symList = pRuntime->get_GlobalSymbolList();
                symbolref pListSym = pList->get_Symbol();
                SymbolRef iterSymbol = FindTemplateType( symList, t_listiter, pListSym->m_dwTemplSpecType );
                iRet = pIter->Init( &iterSymbol, NULL );
                if( iRet != XORT_OK ) {
                    delete pIter;
                    return iRet;
                }
            }

            retVal.SetValue( pIter ); // +ref
            retVal.bType = t_p;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal );
            break;
        }

    case 14: // 14 ListIterator erase( ListIterator iter );
        {
            if( dwArgsCount != 1 ) return ERR_INVALID_ARG_COUNT;

            XortElement& argItem = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != t_p ) return ERR_INVALID_TYPE;
            xobjectref pListIter = (xobjectref)argItem._p;
            if( !pListIter ) return ERR_INVALID_ARG;
            if( pListIter->GetType() != t_listiter ) return ERR_INVALID_TYPE;

            CXListIteratorImpl<ListType, ListClass> *pIter = (CXListIteratorImpl<ListType, ListClass> *)pListIter;
            if( pIter->GetTemplateType() != pList->GetTemplateType() ) return ERR_INVALID_TYPE;

            typename ListClass::iterator newIter = pList->erase( pIter->get_Iterator() );
            typename ListClass::iterator theIterBegin = pList->begin();
            typename ListClass::iterator theIterEnd = pList->end();

            CXListIteratorImpl<ListType, ListClass> *pNewIter = new CXListIteratorImpl<ListType, ListClass>( theIterBegin, theIterEnd, newIter, typeValue );
            if( !pNewIter )
                return ERR_MEMORY_ALLOCATION;

            symbolref pIterSymbol = CXListIteratorImpl<ListType, ListClass>::__GetSymbol();
            if( pIterSymbol ) { // fast way, try to get symbol from the same iterator type if any
                pNewIter->Init( pIterSymbol, NULL );
            } else { // looks like we create this iterator for the first time, look to symbol table
                SYMBOLLIST symList = pRuntime->get_GlobalSymbolList();
                symbolref pListSym = pList->get_Symbol();
                SymbolRef iterSymbol = FindTemplateType( symList, t_listiter, pListSym->m_dwTemplSpecType );
                iRet = pNewIter->Init( &iterSymbol, NULL );
                if( iRet != XORT_OK ) {
                    delete pNewIter;
                    return iRet;
                }
            }

            retVal.SetValue( pNewIter ); // +ref
            retVal.bType = t_p;

            iRet = pRuntime->do_ret( retPrim );
            if( iRet != XORT_OK ) return iRet;

            stack.push( retVal );
            break;
        }

    default:
        return ERR_METHOD_NOT_FOUND;
    }

    return XORT_OK;
}
//////////////////////////////////////////////////////////////////////////
// xlist

class xlist_s1 : public xlist<char,  CCopySimpleType<char>, CDeleteSimpleType<char> >
{
public:
    xlist_s1() { m_dwTemplateType = t_s1; }
    virtual ~xlist_s1() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_s1, char, t_s1>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_u1 : public xlist<byte,  CCopySimpleType<byte>, CDeleteSimpleType<byte> >
{
public:
    xlist_u1() { m_dwTemplateType = t_u1; }
    virtual ~xlist_u1() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_u1, byte, t_u1>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_s2 : public xlist<short, CCopySimpleType<short>, CDeleteSimpleType<short> >
{
public:
    xlist_s2() { m_dwTemplateType = t_s2; }
    virtual ~xlist_s2() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_s2, short, t_s2>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_u2 : public xlist<word,  CCopySimpleType<word>, CDeleteSimpleType<word> >
{
public:
    xlist_u2() { m_dwTemplateType = t_u2; }
    virtual ~xlist_u2() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_u2, word, t_u2>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_s4 : public xlist<int,   CCopySimpleType<int>, CDeleteSimpleType<int> >
{
public:
    xlist_s4() { m_dwTemplateType = t_s4; }
    virtual ~xlist_s4() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_s4, int, t_s4>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_u4 : public xlist<dword, CCopySimpleType<dword>, CDeleteSimpleType<dword> >
{
public:
    xlist_u4() { m_dwTemplateType = t_u4; }
    virtual ~xlist_u4() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_u4, dword, t_u4>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_s8 : public xlist<qlong, CCopySimpleType<qlong>, CDeleteSimpleType<qlong> >
{
public:
    xlist_s8() { m_dwTemplateType = t_s8; }
    virtual ~xlist_s8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_s8, qlong, t_s8>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_u8 : public xlist<qword, CCopySimpleType<qword>, CDeleteSimpleType<qword> >
{
public:
    xlist_u8() { m_dwTemplateType = t_u8; }
    virtual ~xlist_u8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_u8, qword, t_u8>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_r4 : public xlist<float, CCopySimpleType<float>, CDeleteSimpleType<float> >
{
public:
    xlist_r4() { m_dwTemplateType = t_r4; }
    virtual ~xlist_r4() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_r4, float, t_r4>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_r8 : public xlist<real,  CCopySimpleType<real>, CDeleteSimpleType<real> >
{
public:
    xlist_r8() { m_dwTemplateType = t_r8; }
    virtual ~xlist_r8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_r8, real, t_r8>( this, dwFuncIndex, pRuntime );
    }
};

class xlist_xo : public xlist<xobjectref,  CCopyObject<xobjectref>, CDeleteObject<xobjectref> >
{
public:
    xlist_xo() { m_dwTemplateType = t_p; }
    virtual ~xlist_xo() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeListMethod<xlist_xo, xobjectref, t_p>( this, dwFuncIndex, pRuntime );
    }
};

//////////////////////////////////////////////////////////////////////////
// array
template<class ArrayClass, typename ArrayType, int typeValue>
int InvokeArrayMethod( ArrayClass *pArray, dword dwFuncIndex, XRuntime *pRuntime )
{
    int iRet = XORT_OK;

    XCELLSARRAY& stack = pRuntime->get_Stack();
    const XortElement& sysFrame = stack.top();
    if( sysFrame.bAccess != sys_Frame ) return ERR_INVALID_STACK_SYSFRAME;
    dword dwArgsCount = sysFrame.bType;
    dword dwStackBase = pRuntime->get_StackBase();

    InstructionData retPrim; retPrim.m_bInstrCode = p_ret; retPrim.m_bTypeAddr = t_v; // prepare ret primitive
    XortElement retVal; retVal.bAccess = usr_VarRW; // prepare return value

    switch( dwFuncIndex )
    {
    case 1: // 1. dword reserve( dword dwNumItems )
        {
            if( dwArgsCount != 1 ) // no arguments ??
                return ERR_INVALID_ARG_COUNT;

            XortElement& argNumItems  = stack.get( dwStackBase - dwArgsCount );
            if( argNumItems.bType != t_u4 ) return ERR_INVALID_TYPE;
            if( argNumItems._u4 == 0 ) return ERR_INVALID_ARG;

            retVal._u4   = pArray->reserve( argNumItems._u4 ); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure to the stack
            break;
        }

    case 2: // 2. dword allocated();
        {
            if( dwArgsCount != 0 ) // arguments ??
                return ERR_INVALID_ARG_COUNT;

            retVal._u4   = pArray->allocated(); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            // push the result of procedure
            stack.push( retVal );
            break;
        }

    case 3: // 3. dword add( const T& Item );
        {
            if( dwArgsCount != 1 ) // check arguments
                return ERR_INVALID_ARG_COUNT;

            XortElement& argItem  = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != pArray->GetTemplateType() || argItem.bType != typeValue ) return ERR_INVALID_TYPE;

            retVal._u4   = pArray->add( (ArrayType)argItem ); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure to the stack
            break;
        }

    case 4: // 4. dword del();
        {
            if( dwArgsCount != 0 ) // arguments ??
                return ERR_INVALID_ARG_COUNT;

            retVal._u4   = pArray->del(); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure
            break;
        }

    case 5: // 5. void clear();
        {
            if( dwArgsCount != 0 ) // arguments ??
                return ERR_INVALID_ARG_COUNT;

            pArray->clear(); // invoke function

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;
            break;
        }

    case 6: // 6. void zero();
        {
            if( dwArgsCount != 0 ) // arguments ??
                return ERR_INVALID_ARG_COUNT;

            pArray->zero(); // invoke function

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;
            break;
        }

    case 7: // 7. dword put( dword idx, const T& Item );
        {
            if( dwArgsCount != 2 ) // check arguments
                return ERR_INVALID_ARG_COUNT;

            XortElement& argIndex  = stack.get( dwStackBase - dwArgsCount );
            if( argIndex.bType != t_u4 ) return ERR_INVALID_TYPE;

            XortElement& argItem  = stack.get( dwStackBase - (dwArgsCount-1) );
            if( argItem.bType != pArray->GetTemplateType() || argItem.bType != typeValue ) return ERR_INVALID_TYPE;

            retVal._u4   = pArray->put( argIndex._u4, (ArrayType)argItem ); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal );      // push the result of procedure to the stack
            break;
        }

    case 8: // 8. T& get( dword idx );
        {
            if( dwArgsCount != 1 ) // check arguments
                return ERR_INVALID_ARG_COUNT;

            XortElement& argIndex  = stack.get( dwStackBase - dwArgsCount );
            if( argIndex.bType != t_u4 ) return ERR_INVALID_TYPE;

            ArrayType val = pArray->get( argIndex._u4 ); // invoke function
            retVal.SetValue( val );
            retVal.bType = typeValue;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure to the stack
            break;

        }

    case 9: // 9. dword count();
        {
            if( dwArgsCount != 0 ) // arguments ??
                return ERR_INVALID_ARG_COUNT;

            retVal._u4   = pArray->count(); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            // push the result of procedure
            stack.push( retVal );
            break;
        }

    case 10: // 10. dword copy( array<T> ar );
        {
            if( dwArgsCount != 1 ) // check arguments
                return ERR_INVALID_ARG_COUNT;

            XortElement& argItem  = stack.get( dwStackBase - dwArgsCount );
            if( argItem.bType != t_p )
                return ERR_INVALID_TYPE;
            if( argItem._p == NULL )
                return ERR_INVALID_ARG;
            
            symbolref pSymArg = argItem._p->get_Symbol();
            if( pSymArg->m_dwTemplateType != t_array )
                return ERR_INVALID_TYPE;

            symbolref pSymThis = pArray->get_Symbol();
            if( pSymThis->m_dwTemplSpecType != pSymArg->m_dwTemplSpecType )
                return ERR_INVALID_TYPE;

            ArrayClass *pArr = (ArrayClass*)argItem._p;

            retVal._u4   = pArray->copy( *pArr ); // invoke function
            retVal.bType = t_u4;

            iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
            if( iRet != XORT_OK )
                return iRet;

            stack.push( retVal ); // push the result of procedure to the stack
            break;

        }
    default: 
        return ERR_METHOD_NOT_FOUND;
    }
    return XORT_OK;
}

//////////////////////////////////////////////////////////////////////////
// typed classes:
class xarray_s1 : public xarray<char,  CCopySimpleType<char>, CDeleteSimpleType<char> >
{
public:
    xarray_s1() { m_dwTemplateType = t_s1; }
    virtual ~xarray_s1() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_s1, char, t_s1>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_u1 : public ByteArray // this class also works as memory stream and has additional functions
{
public:
    xarray_u1() { m_dwTemplateType = t_u1; }
    virtual ~xarray_u1() { ; }
    
IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        if( dwFuncIndex >= 1 && dwFuncIndex <= 10 ) // early return in case of standard method
            return InvokeArrayMethod<xarray_u1, byte, t_u1>( this, dwFuncIndex, pRuntime );

        // the rest of stream functions
        int iRet = XORT_OK;

        XCELLSARRAY& stack = pRuntime->get_Stack();
        const XortElement& sysFrame = stack.top();
        if( sysFrame.bAccess != sys_Frame ) return ERR_INVALID_STACK_SYSFRAME;
        dword dwArgsCount = sysFrame.bType;
        dword dwStackBase = pRuntime->get_StackBase();

        InstructionData retPrim; retPrim.m_bInstrCode = p_ret; retPrim.m_bTypeAddr = t_v; // prepare ret primitive
        XortElement retVal; retVal.bAccess = usr_VarRW; // prepare return value

        if( dwArgsCount != 1 ) // no arguments ??
            return ERR_INVALID_ARG_COUNT;

        XortElement& argValue  = stack.get( dwStackBase - dwArgsCount );

        switch( dwFuncIndex )
        {
        case 11: // 11 dword storeByte( byte b )
            {
                if( argValue.bType != t_u1 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeByte( argValue._u1 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 12: // 12 byte getByte( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u1   = getByte( argValue._u4 ); // invoke function
                retVal.bType = t_u1;
                break;
            }

        case 13: // 13 dword storeShort( short s )
            {
                if( argValue.bType != t_s2 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeShort( argValue._s2 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 14: // 14 short getShort( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._s2   = getShort( argValue._u4 ); // invoke function
                retVal.bType = t_s2;
                break;
            }

        case 15: // 15 dword storeWord( word w )
            {
                if( argValue.bType != t_u2 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeWord( argValue._u2 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 16: // 16 word getWord( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u2   = getWord( argValue._u4 ); // invoke function
                retVal.bType = t_u2;
                break;
            }

        case 17: // 17 dword storeInt( int i )
            {
                if( argValue.bType != t_s4 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeInt( argValue._s4 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 18: // 18 int   getInt( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._s4   = getInt( argValue._u4 ); // invoke function
                retVal.bType = t_s4;
                break;
            }

        case 19: // 19 dword storeDword( dword d )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeDword( argValue._u4 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 20: // 20 dword getDword( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u4   = getDword( argValue._u4 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 21: // 21 dword storeLong( qlong l )
            {
                if( argValue.bType != t_s8 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeLong( argValue._s8 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 22: // 22 qlong getLong( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._s8   = getLong( argValue._u4 ); // invoke function
                retVal.bType = t_s8;
                break;
            }

        case 23: // 23 dword storeQword( qword q )
            {
                if( argValue.bType != t_u8 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeQword( argValue._u8 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 24: // 24 qword getQword( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u8   = getQword( argValue._u4 ); // invoke function
                retVal.bType = t_u8;
                break;
            }

        case 25: // 25 dword storeFloat( float f )
            {
                if( argValue.bType != t_r4 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeFloat( argValue._r4 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 26: // 26 float getFloat( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._r4   = getFloat( argValue._u4 ); // invoke function
                retVal.bType = t_r4;
                break;
            }

        case 27: // 27 dword storeDouble( double r )
            {
                if( argValue.bType != t_r8 ) return ERR_INVALID_TYPE;
                retVal._u4   = storeDouble( argValue._r8 ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 28: // 28 double getDouble( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._r8   = getDouble( argValue._u4 ); // invoke function
                retVal.bType = t_r8;
                break;
            }

        case 29: // 29 dword storePointer( void *p )
            {
                if( argValue.bType != t_p ) return ERR_INVALID_TYPE;
                retVal._u4   = storePointer( argValue._p ); // invoke function
                retVal.bType = t_u4;
                break;
            }

        case 30: // 30 void* getPointer( dword dwAtIndex )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._p    = getPointer( argValue._u4 ); // invoke function
                retVal.bType = t_p;
                break;
            }

        case 31: // 31 dword set_itemsCount( dword dwVal )
            {
                if( argValue.bType != t_u4 ) return ERR_INVALID_TYPE;
                retVal._u4   = set_itemsCount( argValue._u4 ); // invoke function
                retVal.bType = t_u4;
                break;
            }
        default:
            return ERR_METHOD_NOT_FOUND;
        }

        iRet = pRuntime->do_ret( retPrim ); // clean the XVM stack
        if( iRet != XORT_OK )
            return iRet;

        stack.push( retVal ); // push the result of procedure to the stack
        return XORT_OK;
    }
};

class xarray_s2 : public xarray<short, CCopySimpleType<short>, CDeleteSimpleType<short> >
{
public:
    xarray_s2() { m_dwTemplateType = t_s2; }
    virtual ~xarray_s2() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_s2, short, t_s2>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_u2 : public xarray<word,  CCopySimpleType<word>, CDeleteSimpleType<word> >
{
public:
    xarray_u2() { m_dwTemplateType = t_u2; }
    virtual ~xarray_u2() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_u2, word, t_u2>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_s4 : public xarray<int,   CCopySimpleType<int>, CDeleteSimpleType<int> >
{
public:
    xarray_s4() { m_dwTemplateType = t_s4; }
    virtual ~xarray_s4() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_s4, int, t_s4>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_u4 : public xarray<dword, CCopySimpleType<dword>, CDeleteSimpleType<dword> >
{
public:
    xarray_u4() { m_dwTemplateType = t_u4; }
    virtual ~xarray_u4() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_u4, dword, t_u4>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_s8 : public xarray<qlong, CCopySimpleType<qlong>, CDeleteSimpleType<qlong> >
{
public:
    xarray_s8() { m_dwTemplateType = t_s8; }
    virtual ~xarray_s8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_s8, qlong, t_s8>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_u8 : public xarray<qword, CCopySimpleType<qword>, CDeleteSimpleType<qword> >
{
public:
    xarray_u8() { m_dwTemplateType = t_u8; }
    virtual ~xarray_u8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_u8, qword, t_u8>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_r4 : public xarray<float, CCopySimpleType<float>, CDeleteSimpleType<float> >
{
public:
    xarray_r4() { m_dwTemplateType = t_r4; }
    virtual ~xarray_r4() { ; }
    
IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_r4, float, t_r4>( this, dwFuncIndex, pRuntime );
    }

};

class xarray_r8 : public xarray<real,  CCopySimpleType<real>, CDeleteSimpleType<real> >
{
public:
    xarray_r8() { m_dwTemplateType = t_r8; }
    virtual ~xarray_r8() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_r8, real, t_r8>( this, dwFuncIndex, pRuntime );
    }
};

class xarray_xo : public xarray<xobjectref,  CCopyObject<xobjectref>, CDeleteObject<xobjectref> >
{
public:
    xarray_xo() { m_dwTemplateType = t_p; }
    virtual ~xarray_xo() { ; }

IMPLEMENT_OBJECT_INFO();

    virtual int Invoke( dword dwFuncIndex, XRuntime *pRuntime )
    {
        return InvokeArrayMethod<xarray_xo, xobjectref, t_p>( this, dwFuncIndex, pRuntime );
    }
};

#endif // __XVM__